namespace detail {

/**
 * A structure to contain a value of any type,
 * and a contextual information - the socket
 * to the client.
 *
 * It is dangerous to pass around a raw pointer
 * to a socket. Usually, we would pass a client
 * identifier instead, and have the central
 * server component keep track of all clients.
 */
template <typename MessageType>
struct with_client {
    MessageType value;
    tcp::socket *socket;

    void reply(const std::string& message) const
    {
        boost::asio::async_write(
                *socket,
                boost::asio::buffer(message, message.length()),
                                 [](auto, auto) {});
    }
};

} // namespace detail

/**
 * Function that constructs an instance of with_client given a
 * value and a socket
 */
template <typename MessageType>
auto make_with_client(MessageType&& value, tcp::socket* socket)
{
    return ::detail::with_client<MessageType>{
        std::forward<MessageType>(value), socket};
}

/**
 * Lift any function from T1 to T2 to a function
 * from with_client<T1> to with_client<T2>
 */
template <typename F>
auto lift_with_client(F&& function)
{
    return [function = std::forward<F>(function)] (auto &&ws) {
        return make_with_client(std::invoke(function, ws.value), ws.socket);
    };
}

/**
 * Converts a function from T1 to T2 to a
 * function from with_client<T1> to T2.
 * This is not a given thing for all monads,
 * but we need it to be able to use the filter
 * transformation on streams that emit values
 * with socket pointer
 */
template <typename F>
auto apply_with_client(F&& function)
{
    return [function = std::forward<F>(function)] (auto &&ws) {
        return std::invoke(function, std::forward<decltype(ws)>(ws).value);
    };
}

template<typename EmitFunction>
class session:
    public std::enable_shared_from_this<session<EmitFunction>> {
        public:
            session(tcp::socket && socket, EmitFunction emit)
                : m_socket(std::move(socket))
                , m_emit(emit)
            {

            }

            void start()
            {
                do_read();
            }
        private:
            using shared_session = std::enable_shared_from_this<session<EmitFunction>>;
        
        void do_read()
        {
            // 创建另一个session的共享指针
            auto self = shared_session::shared_from_this();

            boost::asio::async_read_until(
                m_socket, m_data, '\n',
                [this, self](const error_code &error, std::size_t size) {
                    if (!error) {
                        // 可能遇到错误，或者读取一行，并把它发送给注册的消息监听者
                        std::istream is( &m_data);
                        std::string line;
                        std::getline(is, line);
                        m_emit(std::move(line));
                        //读取下一条
                        do_read();
                    }
                }
            )
        }
    };